package MathCore.Operators;

import MathCore.Lexeme;
import MathCore.Operand;
import MathCore.Operands.List;
import MathCore.Operands.Number;
import MathCore.Real;

/**
 *
 * @author Александр
 */
public class ListFunction extends Function
{
	public static final int SUM =0;
	public static final int AVG =1;
	public static final int MIN =2;
	public static final int MAX =3;

	public ListFunction(int type)
	{
		this.type = type;
	}

	public Operand exec(Operand[] operands) throws OperatorException
	{
		if(operands.length != params())
			throw new OperatorException("Неправильное количество операндов у функции "+toString()+". Необходимо "+params()+".");

		if(only(operands, List.class))
		{
			List list = (List) operands[0];
			switch(type)
			{
				case SUM:
				{
					Operand result;
					Operand[] params = new Operand[2];
					ArOperator plus = new ArOperator(ArOperator.ADDITION);

					result = list.get(0);
					for(int i = 1; i<list.size(); i++)
					{
						params[0] = result;
						params[1] = list.get(i);
						result = plus.exec(params);
					}
					return result;
				}
				case AVG:
				{
					ListFunction sum = new ListFunction(ListFunction.SUM);
					ArOperator div = new ArOperator(ArOperator.DIVISION);

					Operand[] params = new Operand[1];
					params[0] = list;

					Operand[] params2 = new Operand[2];
					params2[0] = sum.exec(params);
					params2[1] = new Number(list.size());
					return div.exec(params2);
				}
				case MAX:
				{
					Operand max = null;
					Number modmax = null;
					BasicFunction abs = new BasicFunction(BasicFunction.ABS);
					Operand[] params = new Operand[1];

					for(int i = 0; i<list.size(); i++)
					{
						Operand now = list.get(i);
						if(now instanceof List)
						{
							params[0] = now;
							now = exec(params);
						}
						params[0] = now; // to return
						Operand mod = abs.exec(params);
						if(mod instanceof List)
						{
							params[0] = mod;
							mod = exec(params);
						}
						else
						{
							if(modmax == null)
							{
								modmax = (Number) mod;
								max = now;
							}
							else if(modmax.get().lessThan(((Number)mod).get()))
							{
								modmax = (Number) mod;
								max = now;
							}
						}
					}

					return max;
				}
				case MIN:
				{
					Operand min = null;
					Number modmin = null;
					BasicFunction abs = new BasicFunction(BasicFunction.ABS);
					Operand[] params = new Operand[1];

					for(int i = 0; i<list.size(); i++)
					{
						Operand now = list.get(i);
						if(now instanceof List)
						{
							params[0] = now;
							now = exec(params);
						}
						params[0] = now; // to return
						Operand mod = abs.exec(params);
						if(mod instanceof List)
						{
							params[0] = mod;
							mod = exec(params);
						}
						else
						{
							if(modmin == null)
							{
								modmin = (Number) mod;
								min = now;
							}
							else if(modmin.get().greaterThan(((Number)mod).get()))
							{
								modmin = (Number) mod;
								min = now;
							}
						}
					}

					return min;
				}
			}

			throw new OperatorException(OperatorException.UNSUPPORTED_COMBINATION);
		}
		else
		{
			throw new OperatorException(OperatorException.UNSUPPORTED_COMBINATION);
		}
	}

	public int params()
	{
		return 1;
	}

	public String toString()
	{
		switch(type)
		{
			case SUM: return "sum";
			case AVG: return "avg";
			case MIN: return "min";
			case MAX: return "max";
		}
		return "";
	}

	public Lexeme clone()
	{
		return new ListFunction(type);
	}

}
